package org.eclipsex.sukiyuki.delicious;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.internal.views.markers.ExtendedMarkersView;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.MarkerUtilities;
import org.osgi.framework.BundleContext;

/**
 * 
 * @author sukiyuki
 */
@SuppressWarnings("restriction")
public class DeliciousPlugin extends AbstractUIPlugin {

	// The plug-in ID
	public static final String PLUGIN_ID = "org.eclipsex.sukiyuki.delicious";

	// The shared instance
	private static DeliciousPlugin plugin = null;
	private static IWorkbenchWindow window = null;
	private static IWorkbenchPage page = null;
	private static IEditorPart editorPart = null;
	private static AbstractTextEditor editor = null;
	private static ISelection selection = null;

	public DeliciousPlugin() {
	}

	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;
	}

	public void stop(BundleContext context) throws Exception {
		plugin = null;
		super.stop(context);
	}

	/**
	 * Returns the shared instance
	 * 
	 * @return the shared instance
	 */
	public static DeliciousPlugin getDefault() {
		return plugin;
	}

	/**
	 * Returns an image descriptor for the image file at the given plug-in
	 * relative path
	 * 
	 * @param path
	 *            the path
	 * @return the image descriptor
	 */
	public static ImageDescriptor getImageDescriptor(String path) {
		return imageDescriptorFromPlugin(PLUGIN_ID, path);
	}

	public void bringBookmarkViewToTop(ExecutionEvent event) {
		initial(event);
		if (page == null) {
			return;
		}
		IViewPart view = page.findView(IPageLayout.ID_BOOKMARKS);
		if (view == null) {
			try {
				view = page.showView(IPageLayout.ID_BOOKMARKS);
			} catch (PartInitException e) {
				handleException(e);
			}
		}
		page.bringToTop(view);
	}

	public void clearAllBookmarks(ExecutionEvent event) {
		initial(event);
		if (editor == null) {
			return;
		}
		selection = editor.getSelectionProvider().getSelection();
		if (selection instanceof TextSelection) {
			final IResource resource = (IResource) editor.getEditorInput()
					.getAdapter(IFile.class);
			try {
				resource.deleteMarkers(IMarker.BOOKMARK, true,
						IResource.DEPTH_ZERO);
			} catch (CoreException e) {
				handleException(e);
			}
		}
	}

	public void previousBookmark(ExecutionEvent event) {
		gotoBookmark(event, false);
	}

	public void nextBookmark(ExecutionEvent event) {
		gotoBookmark(event, true);
	}

	public void gotoBookmark(ExecutionEvent event, boolean next) {
		initial(event);
		if (editor == null) {
			return;
		}
		selection = editor.getSelectionProvider().getSelection();
		if (selection instanceof TextSelection) {
			IResource resource = (IResource) editor.getEditorInput()
					.getAdapter(IFile.class);
			int startLine = -1;
			if (!selection.isEmpty()) {
				startLine = ((TextSelection) selection).getStartLine();
				startLine = startLine == -1 ? -1 : startLine + 1;
			}
			Map<Integer, IMarker> map = new HashMap<Integer, IMarker>();
			map.put(startLine, null);
			TreeSet<Integer> set = new TreeSet<Integer>();
			set.add(startLine);
			IMarker[] markers = null;
			try {
				markers = resource.findMarkers(IMarker.BOOKMARK, true,
						IResource.DEPTH_ZERO);
				for (IMarker marker : markers) {
					Integer lineNum = (Integer) marker
							.getAttribute(IMarker.LINE_NUMBER);
					map.put(lineNum, marker);
					set.add(lineNum);
				}
			} catch (CoreException e) {
				handleException(e);
			}
			IMarker marker = null;
			if (set.size() > 1) {
				if (next) {
					if (set.last().equals(startLine)) {
						marker = map.get(set.first());
					} else {
						marker = map.get(set.higher(startLine));
					}
				} else {
					if (set.first().equals(startLine)) {
						marker = map.get(set.last());
					} else {
						marker = map.get(set.lower(startLine));
					}
				}
				ExtendedMarkersView.openMarkerInEditor(marker, page);
			}
			map = null;
			set = null;
		}
	}

	public void toggleBookmark(ExecutionEvent event) {
		initial(event);
		if (editor == null) {
			return;
		}
		selection = editor.getSelectionProvider().getSelection();
		if (selection instanceof TextSelection) {
			TextSelection textSelection = (TextSelection) selection;
			IResource resource = (IResource) editor.getEditorInput()
					.getAdapter(IFile.class);
			IMarker[] markers;
			int line = 0;
			int start = 0;
			int length = 0;
			String content = null;
			IDocument document = editor.getDocumentProvider().getDocument(
					editor.getEditorInput());
			try {
				markers = resource.findMarkers(IMarker.BOOKMARK, true,
						IResource.DEPTH_ZERO);
				for (IMarker marker : markers) {
					if (MarkerUtilities.getLineNumber(marker) == textSelection
							.getStartLine() + 1) {
						marker.delete();
						return;
					}
				}
			} catch (CoreException e) {
				handleException(e);
			}
			line = textSelection.getStartLine();
			try {
				length = document.getLineLength(line);
				start = document.getLineOffset(line);
				content = document.get(start, length).trim();
			} catch (BadLocationException e) {
				handleException(e);
			}
			if (length < 0) {
				length = -length;
				start -= length;
			}
			char[] cs = content.toCharArray();
			int i = 0;
			char[] ac;
			int k = (ac = cs).length;
			for (int j = 0; j < k; j++) {
				char c = ac[j];
				if (!Character.isWhitespace(c)) {
					i++;
				}
			}
			if (i == 0) {
				return;
			}
			IMarker marker;
			try {
				marker = resource.createMarker(IMarker.BOOKMARK);
				if (marker.exists()) {
					marker.setAttribute(IMarker.CHAR_START, start);
					marker.setAttribute(IMarker.CHAR_END, start);
					marker.setAttribute(IMarker.LINE_NUMBER, line == -1 ? -1
							: line + 1);
					marker.setAttribute(IMarker.MESSAGE, content);
				}
			} catch (CoreException e) {
				handleException(e);
			}
		}
	}

	private void initial(final ExecutionEvent event) {
		window = null;
		page = null;
		editorPart = null;
		editor = null;
		selection = null;
		SafeRunner.run(new ISafeRunnable() {
			@Override
			public void run() throws Exception {
				window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
				page = window.getActivePage();
				editorPart = page.getActiveEditor();;
			}

			@Override
			public void handleException(Throwable exception) {
				handleException(exception);
			}
		});
		if (editorPart instanceof AbstractTextEditor) {
			editor = (AbstractTextEditor) editorPart;
		} else if (editorPart instanceof MultiPageEditorPart) {
			Object obj = ((MultiPageEditorPart) editorPart).getSelectedPage();
			if (obj instanceof AbstractTextEditor) {
				editor = (AbstractTextEditor) obj;
			}
		}
	}

	private void handleException(Exception e) {
		IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME,
				IStatus.ERROR, e.getMessage(), e);
		DeliciousPlugin.getDefault().getLog().log(status);
	}
}
